import json
import sys
import csv
from datetime import datetime

from PyQt6 import QtCharts, QtCore
from PyQt6.QtCore import pyqtSlot, QTimer
from PyQt6.QtCore import Qt, QTimer
from PyQt6.QtGui import QFont
from PyQt6.QtGui import QPainter
from PyQt6.QtWidgets import QApplication, QMainWindow, QFileDialog

from sllurp.gui import readerClasses
from sllurp.reader import R420, Reader, ARU2400, FX9600
from sllurp.ui.qt_gui import Ui_Form

readerClasses = {
    'Generic': Reader,
    'R420': R420,
    'ARU2400': ARU2400,
    'FX9600': FX9600
}
freq_table = [
    920.625, 920.875, 921.125, 921.375,
    921.625, 921.875, 922.125, 922.375,
    922.625, 922.875, 923.125, 923.375,
    923.625, 923.875, 924.125, 924.375
]


class InventoryApp(QMainWindow, Ui_Form):
    def __init__(self, parent=None):
        super(InventoryApp, self).__init__()
        self.select_index = 0
        self.reader = None  # 读取器对象
        self.tags = []  # 存储读取到的标签列表
        self.trackedTags = []  # 存储跟踪的标签列表
        self.sorted_tags = {}  # 根据EPC分类存储的字典
        self.isRSSISelected = True  # 画图是否绘制RSSI

        self.select_index = 0
        self.lineSeries = None

        self.counter = 0
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update_time)
        self.timer.start(1000)  # 1000 milliseconds = 1 second

        QMainWindow.__init__(self, parent=parent)

        self.setupUi(self)

        self.btnConnect.clicked.connect(self.connect)

        self.tagsDetected.clicked.connect(self.selectTag)

        self.trackBtn.clicked.connect(self.trackTags)

        self.clearBtn.clicked.connect(self.clearTrackedTags)

        self.changeMetricBtn.clicked.connect(self.changeMetric)

        self.changeMetricBtn.setEnabled(False)

        self.init_chart()
        self.show()

    def update_time(self):
        self.counter += 1
        self.safe_draw()

    def safe_draw(self):
        if not self.sorted_tags:
            return
        # 获取选择的EPC
        selected_epc = list(self.sorted_tags.keys())[self.select_index]
        # 获取该EPC对应的标签列表
        tag_list = self.sorted_tags[selected_epc]
        self.plot_graph(tag_list)

    def init_chart(self):
        # 创建QtCharts中的QChartView
        self.infoChart.setRenderHint(QPainter.RenderHint.Antialiasing)  # 设置抗锯齿效果
        self.infoChart.setFixedSize(400, 400)

        # 创建折线图
        self.lineSeries = QtCharts.QLineSeries()
        self.lineSeries.setName("折线图")

        # 向折线图添加数据点
        self.lineSeries.append(0, 1)
        self.lineSeries.append(1, 3)
        self.lineSeries.append(2, 7)
        self.lineSeries.append(3, 5)
        self.lineSeries.append(4, 9)

        # 创建QChart对象并将折线图添加到其中
        self.chart = QtCharts.QChart()
        self.chart.addSeries(self.lineSeries)
        self.chart.setTitle("折线图示例")
        self.chart.createDefaultAxes()  # 创建默认坐标轴

        # 将QChart对象设置给QChartView
        self.infoChart.setChart(self.chart)

    def draw(self, points, name):
        try:
            # 清空折线图
            self.chart.removeAllSeries()

            # 设置标题
            if self.isRSSISelected:
                self.chart.setTitle('RFID Chart')
            else:
                self.chart.setTitle('Phase Angle Chart')

            # 创建折线图
            self.lineSeries = QtCharts.QLineSeries()
            self.lineSeries.setName(str(name, 'utf-8'))

            # 向折线图添加数据点
            for x, y in points:
                # x = datetime.strptime(x, "%Y-%m-%d %H:%M:%S").timestamp()
                self.lineSeries.append(x, y)

            # 将折线图添加到QChart对象中
            self.chart.addSeries(self.lineSeries)
            self.chart.createDefaultAxes()  # 创建默认坐标轴
        except:
            # 输出错误信息
            print("Error:", sys.exc_info()[0])

    def connect(self):
        # 构建设置
        # self.buildSettings()

        if not self.reader:
            try:
                reader_class = readerClasses[self.model_combo.currentText()]
                print(self.port_edit.text())
                self.reader = reader_class(self.ip_edit.text(), self.port_edit.text())

            except:
                pass
            else:
                self.buildSettings()
                self.LiveButton.setEnabled(True)
                self.SingleButton.setEnabled(True)
                self.SaveButton.setEnabled(True)
                self.btnConnect.setDisabled(True)
                self.FrequencyBox.setEnabled(True)
                self.TxPowerSpinbox.setEnabled(True)
                self.ModeBox.setEnabled(True)
                self.TagPopulationBox.setEnabled(True)
                self.AntennaBox.setEnabled(True)
                self.SessionBox.setEnabled(True)
                self.changeMetricBtn.setEnabled(True)

    def buildSettings(self):
        # 单次盘存按钮
        # single_inventory_btn = QPushButton('Single inventory')
        self.SingleButton.clicked.connect(self.singleInventory)
        # layout.addWidget(single_inventory_btn, 9, 0, 1, 2)

        # 实时盘存按钮
        # self.liveInventory_btn = QPushButton('Live inventory')
        self.LiveButton.clicked.connect(self.liveInventory)
        # layout.addWidget(self.liveInventory_btn, 10, 0, 1, 2)

        # 保存能力的按钮
        # save_capabilities_btn = QPushButton('Save capabilities')
        self.SaveButton.clicked.connect(self.saveCapabilities)
        # layout.addWidget(save_capabilities_btn, 11, 0, 1, 2)

        # self.FrequencyBox.currentIndexChanged.connect(self.comboBoxChanged)
        # 应用布局到 conf_widget
        # self.conf_widget.setLayout(layout)

    # 选择频率展示数据函数
    # def comboBoxChanged(self):
    #     Frequency = self.FrequencyBox.currentText()

    def displayModeInfos(self):
        modeID = self.ModeBox.currentText()  # 获取当前选择的预设模式
        if not self.reader:
            return

        modes = self.reader.capabilities['RegulatoryCapabilities']['UHFBandCapabilities']['UHFRFModeTable']
        modeInfos = next(v for v in modes.values() if v['ModeIdentifier'] == modeID)

        infos = ''

        # C: EPC HAG T&C一致性标志
        # 跳过，因为不感兴趣

        # M: 谱掩码指示器
        ms = {
            0: 'unknown',
            1: 'single reader',
            2: 'multi reader',
            3: 'dense reader'
        }
        m = ms[modeInfos['M']]
        infos += 'Spectral mask: {}\n'.format(m)

        # PIE: 数据1到数据0符号长度比例的1000倍（1.5...2.0）
        pie = modeInfos['PIE']
        infos += 'PIE ratio: {}\n'.format(pie / 1000)

        # Min/Step/Max Tari: Tari时间（数据0符号的持续时间）以ns为单位
        minTari, stepTari, maxTari = modeInfos['MinTari'], modeInfos['StepTari'], modeInfos['MaxTari']
        infos += 'Tari: '
        if maxTari != minTari:
            infos += '{}...{} ({} step) us\n'.format(minTari / 1000, maxTari / 1000, stepTari / 1000)
        else:
            infos += '{} us\n'.format(minTari / 1000)

        # R: DR值。与BDR一起定义TRcal（TRcal = DR/BDR）
        # 跳过，因为不感兴趣

        # BDR: 反向散射数据速率（bps），即标签频率除以调制因子
        blf = modeInfos['BDR']
        infos += 'Tag data rate: {} bps\n'.format(blf / 1000)

        # Mod: 调制/编码
        mods = {
            0: 'FM0',
            1: 'Miller2',
            2: 'Miller4',
            3: 'Miller8'
        }
        mod = mods[modeInfos['Mod']]
        infos += 'Tag modulation: {}'.format(mod)

        # 将信息显示在标签中
        self.tagInfo.setText(infos)

    def getSettings(self):
        # 从字符串中解析天线端口
        antStr = self.AntennaBox.text()
        antennas = (0,) if 'all' in antStr else tuple(int(a) for a in antStr.split(','))

        # 使用设置进行盘存
        settings = {
            'powerDBm': self.TxPowerSpinbox.value(),
            'freqMHz': float(self.FrequencyBox.currentText()),
            'mode': int(self.ModeBox.currentText()),
            'session': int(self.SessionBox.currentText()),
            'population': self.TagPopulationBox.value(),
            'antennas': antennas
        }
        # print(settings)
        if isinstance(self.reader, R420):
            settings.update({'searchmode': int(self.ModeBox.currentText())})

        return settings

    def singleInventory(self):
        if not self.reader:
            return

        settings = self.getSettings()
        self.tags = self.reader.detectTags(**settings)
        self.listTags()

    def liveInventory(self):
        if not self.reader:
            return

        if self.LiveButton.text() == 'Live Inventory':
            # 开始实时盘存
            settings = self.getSettings()
            settings['timeInterval'] = 1
            settings['tagInterval'] = None
            self.reader.startLiveReports(self.collectTags, **settings)
            self.LiveButton.setText('Stop Inventory')
        else:
            # 停止实时盘存
            self.reader._liveStop.set()
            self.LiveButton.setText('Live Inventory')

    def convert_timestamps(self):
        for epc, tags in self.sorted_tags.items():
            for tag in tags:
                # 将 LastSeenTimestampUTC 转换为日期格式
                if 'LastSeenTimestampUTC' in tag:
                    timestamp_str = tag['LastSeenTimestampUTC']
                    try:
                        timestamp = int(timestamp_str)
                        # 假设时间戳单位是微秒（因为数值很大）
                        timestamp_seconds = timestamp / 1e6
                        tag['LastSeenTimestampUTC'] = datetime.utcfromtimestamp(timestamp_seconds).strftime(
                            '%Y-%m-%d %H:%M:%S')
                    except ValueError:
                        # print(f"Invalid timestamp value: {timestamp_str}")
                        continue

                # 如果需要转换 FirstSeenTimestampUTC 也可以类似处理
                if 'FirstSeenTimestampUTC' in tag:
                    timestamp_str = tag['FirstSeenTimestampUTC']
                    try:
                        timestamp = int(timestamp_str)
                        timestamp_seconds = timestamp / 1e6
                        tag['FirstSeenTimestampUTC'] = datetime.utcfromtimestamp(timestamp_seconds).strftime(
                            '%Y-%m-%d %H:%M:%S')
                    except ValueError:
                        # print(f"Invalid timestamp value: {timestamp_str}")
                        continue

    def listTags(self):
        # 清空标签列表
        # self.tagsHeader.setText('')  # 清空摘要
        # self.tagInfo.setText('')  # 清空所选标签信息

        if not (self.reader and self.tags):
            return
        # 将找到的标签插入列表
        # self.tagsHeader.setText('{} Tags ({} unique)'.format(len(self.tags), len(self.reader.uniqueTags(self.tags))))
        for tag in self.tags:
            # print(tag)
            for data in tag:
                epc = data['EPC-96']
                if epc not in self.sorted_tags:
                    self.sorted_tags[epc] = []
                self.sorted_tags[epc].append(data)
        print(self.sorted_tags)
        self.convert_timestamps()
        self.tagsDetected.clear()  # 清空列表
        for epc, tag in self.sorted_tags.items():
            rssi = tag[len(tag) - 1].get('RSSI', tag[len(tag) - 1].get('PeakRSSI'))
            # 制作RSSI的指示器
            if rssi >= -40:
                stars = '*****'
            elif rssi >= -50:
                stars = '****'
            elif rssi >= -60:
                stars = '***'
            elif rssi >= -70:
                stars = '**'
            else:
                stars = '*'
            # 获取标签ID的最后3位数字
            epc = self.reader.getEPC(tag[len(tag) - 1])
            id = int(epc[-2:], 16)
            # 插入包含EPC、ID和RSSI的行
            self.tagsDetected.addItem('{} (...{}) | {}'.format(epc, id, stars))

        self.tags.clear()

    def collectTags(self, new_tags):
        # 收集实时盘存的标签，按epc合并
        for tag in new_tags:
            print('epc: ' + str(tag['EPC-96'], 'utf-8') + ' time:' + str(tag['LastSeenTimestampUTC']))

        self.tags.append(new_tags)
        self.listTags()

    def saveCapabilities(self):
        filepath, _ = QFileDialog.getSaveFileName(
            self,
            "Save Capabilities",
            "",
            "CSV Files (*.csv);;All Files (*)"
        )
        if filepath and self.reader:
            self.export_to_csv(self.sorted_tags, filepath)

    def changeMetric(self):
        self.isRSSISelected = not self.isRSSISelected

    def trackTags(self):
        if self.reader:
            self.reader.includeEPCs = [self.reader.getEPC(tag) for tag in self.tags]

    def clearTrackedTags(self):
        if self.reader:
            self.reader.includeEPCs = []

    def selectTag(self, selected_index):
        if self.sorted_tags:
            index = selected_index.row()
            # 获取选择的EPC
            selected_epc = list(self.sorted_tags.keys())[index]
            # 获取该EPC对应的标签列表
            tag_list = self.sorted_tags[selected_epc]
            # 获取最新的标签数据（假设是最后一个）
            tag = tag_list[-1]

            tag_info = ''
            for key, val in tag.items():
                # 将键值对转换为字符串并添加到 tag_info 中
                tag_info += '{}: {}\n'.format(key, val)

            # 显示标签信息
            self.tagInfo.setPlainText(tag_info)
            # 绘制折线图
            # self.plot_graph(tag_list)
            self.select_index = index

    @pyqtSlot()
    def safe_draw(self):
        if not self.sorted_tags:
            return
        # 获取选择的EPC
        selected_epc = list(self.sorted_tags.keys())[self.select_index]
        # 获取该EPC对应的标签列表
        tag_list = self.sorted_tags[selected_epc]
        self.plot_graph(tag_list)

    def plot_graph(self, tag_re):
        coords = []
        for tag in tag_re:
            x0 = datetime.strptime(tag['FirstSeenTimestampUTC'], "%Y-%m-%d %H:%M:%S").timestamp()
            x1 = datetime.strptime(tag['LastSeenTimestampUTC'], "%Y-%m-%d %H:%M:%S").timestamp()
            if self.isRSSISelected:
                coords.append([x1 - x0, tag.get['RSSI']])
            else:
                coords.append([x1 - x0, tag['PhaseAngle']])
        # 绘制
        self.draw(coords, tag_re[len(tag_re) - 1]['EPC-96'])

    def export_to_csv(self, data, filename):
        all_rows = []
        for key, value in data.items():
            # 将字典中的 bytes ID 转换为字符串

            for row in value:
                # 将 bytes 类型的字段转换为字符串
                row = {k: (v.decode() if isinstance(v, bytes) else v) for k, v in row.items()}
                # 添加一个新的字段 'ID' 来存储ID
                # row['B_ID'] = key
                row['Frequency/MHz'] = freq_table[row['ChannelIndex'] - 1]
                all_rows.append(row)

            # 提取字典中的字段名（CSV文件的列名）
        if all_rows:
            fieldnames = all_rows[0].keys()
        else:
            print("No data to export.")
            return

            # 写入 CSV 文件
        with open(filename, mode='w', newline='') as file:
            writer = csv.DictWriter(file, fieldnames=fieldnames)

            # 写入表头
            writer.writeheader()

            # 写入所有记录
            writer.writerows(all_rows)

        print(f"CSV file '{filename}' has been created.")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = InventoryApp()
    sys.exit(app.exec())
